Análise de dados - Salários¶
Importando as bibliotecas¶
In [167]:
import pandas as pd # Importa a biblioteca pandas para manipulação de dados
import matplotlib.pyplot as plt # Importa a biblioteca matplotlib para visualização de gráficos
import seaborn as sns # Importa a biblioteca seaborn para gráficos mais sofisticados
import numpy as np
import plotly.express as px
from sklearn.linear_model import LinearRegression
Importando arquivo¶
In [115]:
df = pd.read_csv("salaries.csv")
Tratamento de dados¶
In [116]:
#Verificar os primeiros registros
print(df.head().to_string())
work_year experience_level employment_type job_title salary salary_currency salary_in_usd employee_residence remote_ratio company_location company_size 0 2025 MI FT Customer Success Manager 57000 EUR 60000 NL 50 NL L 1 2025 SE FT Engineer 165000 USD 165000 US 0 US M 2 2025 SE FT Engineer 109000 USD 109000 US 0 US M 3 2025 SE FT Applied Scientist 294000 USD 294000 US 0 US M 4 2025 SE FT Applied Scientist 137600 USD 137600 US 0 US M
In [117]:
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 88584 entries, 0 to 88583 Data columns (total 11 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 work_year 88584 non-null int64 1 experience_level 88584 non-null object 2 employment_type 88584 non-null object 3 job_title 88584 non-null object 4 salary 88584 non-null int64 5 salary_currency 88584 non-null object 6 salary_in_usd 88584 non-null int64 7 employee_residence 88584 non-null object 8 remote_ratio 88584 non-null int64 9 company_location 88584 non-null object 10 company_size 88584 non-null object dtypes: int64(4), object(7) memory usage: 7.4+ MB
In [118]:
#Verifica o tipo de dado
print('Tipagem:\n', df.dtypes)
Tipagem: work_year int64 experience_level object employment_type object job_title object salary int64 salary_currency object salary_in_usd int64 employee_residence object remote_ratio int64 company_location object company_size object dtype: object
In [119]:
#Checar valores nulos
print('Valores nulos:\n', df.isnull().sum())
Valores nulos: work_year 0 experience_level 0 employment_type 0 job_title 0 salary 0 salary_currency 0 salary_in_usd 0 employee_residence 0 remote_ratio 0 company_location 0 company_size 0 dtype: int64
In [120]:
#Verifica a quantidade de registros
print('Qtd: ', df.shape)
Qtd: (88584, 11)
In [121]:
#Padronizar textos
df['job_title'] = df['job_title'].str.lower().str.strip()
In [122]:
print('Estatísticas resumidas para colunas numéricas:')
display(df.describe())
Estatísticas resumidas para colunas numéricas:
| work_year | salary | salary_in_usd | remote_ratio | |
|---|---|---|---|---|
| count | 88584.000000 | 8.858400e+04 | 88584.000000 | 88584.000000 |
| mean | 2024.034758 | 1.619323e+05 | 157567.798417 | 21.286011 |
| std | 0.620370 | 1.965317e+05 | 73531.373158 | 40.831018 |
| min | 2020.000000 | 1.400000e+04 | 15000.000000 | 0.000000 |
| 25% | 2024.000000 | 1.060000e+05 | 106097.250000 | 0.000000 |
| 50% | 2024.000000 | 1.470000e+05 | 146307.000000 | 0.000000 |
| 75% | 2024.000000 | 1.995000e+05 | 198600.000000 | 0.000000 |
| max | 2025.000000 | 3.040000e+07 | 800000.000000 | 100.000000 |
In [123]:
print('Estatísticas resumidas para colunas numéricas:')
display(df.describe(include=object))
Estatísticas resumidas para colunas numéricas:
| experience_level | employment_type | job_title | salary_currency | employee_residence | company_location | company_size | |
|---|---|---|---|---|---|---|---|
| count | 88584 | 88584 | 88584 | 88584 | 88584 | 88584 | 88584 |
| unique | 4 | 4 | 312 | 26 | 96 | 90 | 3 |
| top | SE | FT | data scientist | USD | US | US | M |
| freq | 51596 | 88111 | 13156 | 83994 | 79705 | 79762 | 85667 |
In [124]:
print(df.columns)
Index(['work_year', 'experience_level', 'employment_type', 'job_title',
'salary', 'salary_currency', 'salary_in_usd', 'employee_residence',
'remote_ratio', 'company_location', 'company_size'],
dtype='object')
Processamento de dados¶
In [127]:
print(df["experience_level"].unique())
['Intermediate' 'Senior Expert' 'Junior' 'Executive Director']
In [126]:
experience_level = {
"EN": "Junior",
"MI": "Intermediate",
"SE": "Senior Expert",
"EX": "Executive Director"
}
df["experience_level"] = df["experience_level"].map(experience_level)
In [129]:
employment_type = {
"PT": "Part-Time",
"FT": "Full-Time",
"CT": "Contract-Based",
"FL": "Freelance"
}
df["employment_type"] = df["employment_type"].map(employment_type)
In [130]:
remote_work_ratio = {
0: "On-Site",
50: "Hybrid (50% Remote)",
100: "Fully Remote"
}
df["remote_ratio"] = df["remote_ratio"].map(remote_work_ratio)
In [131]:
company_sizes = {
"S": "Small Business",
"M": "Mid-Sized Company",
"L": "Large Enterprise"
}
df["company_size"] = df["company_size"].map(company_sizes)
In [132]:
salario_por_cargo = df.groupby('job_title')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_cargo.head(10)
Out[132]:
job_title analytics engineering manager 399880.000000 data science tech lead 375000.000000 applied ai ml lead 292500.000000 head of machine learning 283573.545455 machine learning performance engineer 262500.000000 head of ai 261023.076923 engineering manager 258633.717391 enterprise account executive 258258.535714 aws data architect 258000.000000 director of machine learning 256479.545455 Name: salary_in_usd, dtype: float64
Média de salário por país¶
In [133]:
salario_por_pais = df.groupby('employee_residence')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_pais.head(10)
Out[133]:
employee_residence QA 300000.000000 VE 192500.000000 CZ 189519.777778 US 163597.512854 IL 147321.733333 PR 146488.888889 SA 139999.333333 EG 132873.809524 AU 132236.050336 CA 131319.001873 Name: salary_in_usd, dtype: float64
Média de salário por nível de experiência¶
In [134]:
salario_por_experiencia = df.groupby('experience_level')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_experiencia.head(10)
Out[134]:
experience_level Executive Director 200224.101130 Senior Expert 173033.652764 Intermediate 142708.823501 Junior 100316.106908 Name: salary_in_usd, dtype: float64
Média de salário por cargo¶
In [152]:
salario_por_cargo = df.groupby('job_title')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_cargo.head(10)
Out[152]:
job_title analytics engineering manager 399880.000000 data science tech lead 375000.000000 applied ai ml lead 292500.000000 head of machine learning 283573.545455 machine learning performance engineer 262500.000000 head of ai 261023.076923 engineering manager 258633.717391 enterprise account executive 258258.535714 aws data architect 258000.000000 director of machine learning 256479.545455 Name: salary_in_usd, dtype: float64
Média de salário por modelo de trabalho (remoto=fully remote/híbrido=hybrid/presencial=on-site)¶
In [153]:
salario_por_modelo = df.groupby('remote_ratio')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_modelo.head(10)
Out[153]:
remote_ratio On-Site 160196.306970 Fully Remote 148999.106211 Hybrid (50% Remote) 81255.192568 Name: salary_in_usd, dtype: float64
Média de salário em comparação com o tamanho da companhia¶
In [154]:
salario_por_tamanho = df.groupby('company_size')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_tamanho.head(10)
Out[154]:
company_size Mid-Sized Company 157834.736526 Large Enterprise 154475.012209 Small Business 89773.471963 Name: salary_in_usd, dtype: float64
Média de salário por tipo de contrato (Meio período/Integral/Contrato/Freelance)ce"¶
In [157]:
salario_por_tipo = df.groupby('employment_type')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_tipo.head(10)
Out[157]:
employment_type Full-Time 157959.297556 Contract-Based 96016.437500 Part-Time 76034.682403 Freelance 50651.562500 Name: salary_in_usd, dtype: float64
Média de salário por ano¶
In [158]:
salario_por_ano = df.groupby('work_year')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_ano.head(10)
Out[158]:
work_year 2024 159600.360607 2025 155174.567055 2023 153700.755456 2022 134175.359036 2020 102250.866667 2021 99922.073394 Name: salary_in_usd, dtype: float64
In [169]:
# Contagem de registros por país
quantidade_por_pais = df['employee_residence'].value_counts().reset_index()
quantidade_por_pais.columns = ['País', 'Quantidade de Registros']
# Visualizar os 10 países com mais registros
quantidade_por_pais.head(10)
Out[169]:
| País | Quantidade de Registros | |
|---|---|---|
| 0 | US | 79705 |
| 1 | CA | 3203 |
| 2 | GB | 2576 |
| 3 | AU | 298 |
| 4 | DE | 263 |
| 5 | FR | 226 |
| 6 | ES | 203 |
| 7 | LT | 202 |
| 8 | NL | 187 |
| 9 | AT | 173 |
In [180]:
sns.barplot(
data=quantidade_por_pais.head(10),
x='Quantidade de Registros',
y='País',
hue='País',
palette='crest',
dodge=False
)
plt.legend([],[], frameon=False) # isso oculta a legenda sem dar erro
plt.title('Top 10 Países com Maior Número de Registros no Dataset', fontsize=14, fontweight='bold')
plt.xlabel('Número de Registros')
plt.ylabel('País')
plt.grid(True, axis='x', linestyle='--', alpha=0.5)
plt.show()
In [178]:
plt.figure(figsize=(12, 6))
sns.barplot(
x=salario_por_pais.head(10).values,
y=salario_por_pais.head(10).index,
hue=salario_por_pais.head(10).index, # define o hue igual ao y
palette='viridis',
legend=False # remove legenda já que y é hue
)
plt.title('Top 10 Países com Maior Média Salarial (USD)', fontsize=14, fontweight='bold')
plt.xlabel('Salário Médio (USD)', fontsize=12)
plt.ylabel('País de Residência do Funcionário', fontsize=12)
plt.grid(axis='x', linestyle='--', alpha=0.4)
plt.tight_layout()
plt.show()
In [181]:
# Os EUA dominam o conjunto de dados - Sozinho, os Estados Unidos representam mais de 90% do total de registros, nesse caso
# é visível que o dataframe é enviesado para o mercado americano. Em seguida, acompanha o Canadá e o Reino Unido, ainda que distante
# da média salarial dos EUA. E ainda, há pouca representatividade dos outros países (Alemanha, França, Espanha, Lituânia, etc.) por possuirem menos de
# 300 registros.
Relação da média salarial pelo nível de experiência, adicionando o cargo¶
In [144]:
fig = px.scatter(
df,
x="experience_level",
y="salary_in_usd",
size="salary_in_usd",
color="experience_level",
hover_name="job_title", # o que aparece ao passar o mouse
title="Salário vs. Nível de Experiência (com cargo no hover)",
labels={"salary_in_usd": "Salário (USD)", "experience_level": "Nível de Experiência"},
height=600
)
fig.update_traces(marker=dict(opacity=0.5, line=dict(width=1, color='DarkSlateGrey')))
fig.show()
In [ ]:
# Intermediate e Senior Expert representa as maiores concentrações dos pontos, representação a maioria dos profissionais. A variação
# salarial é significativa nesses grupos (baixos e altos salários).
# Junior tem mais pontos concentrados em salários mais baixos, porém alguns destoam com salários bem altos (podendo existir alguma exceção, cargos raros
# ou erros de registros.
# Executive Director tem menos registros, mas uma faixa salarial muito alta e consistente. Pouca dispersão indica padrões salariais mais alinhados,
# o que é comum em altos cargos executivos.
Gráfico de médias saláriais por cargo, de acordo com o tipo de contrato¶
In [147]:
# Agrupa por cargo e tipo de contrato, tirando a média
media_salario = df.groupby(['job_title', 'employment_type'])['salary_in_usd'].mean().reset_index()
# (Opcional) limitar aos cargos mais frequentes pra não poluir
top_cargos = df['job_title'].value_counts().nlargest(10).index
media_salario = media_salario[media_salario['job_title'].isin(top_cargos)]
# Gráfico interativo
fig = px.bar(
media_salario,
x='job_title',
y='salary_in_usd',
color='employment_type',
barmode='group', # barras agrupadas por tipo de contrato
title='Média Salarial por Cargo e Tipo de Contrato',
labels={
'job_title': 'Cargo',
'salary_in_usd': 'Salário Médio (USD)',
'employment_type': 'Tipo de Contrato'
},
height=600
)
fig.update_layout(xaxis_tickangle=-45)
fig.show()
In [ ]:
#Full-Time (vermelho) domina com os maiores salários médios em praticamente todos os cargos.
#Destaque para: Machine Learning Engineer, Research Scientist, Software Engineer
#Nesses cargos, os salários ultrapassam facilmente os $190k.
#Contract-Based (azul):
#É competitivo em algumas áreas como:
#Software Engineer (próximo ou até acima do full-time)
#Data Engineer e Research Scientist
#Indica que contratos por projeto em tech avançada podem pagar muito bem.
#Freelance (roxo):
#Aparece com valores medianos, mas interessante em:
#Machine Learning Engineer (quase $100k)
#Engineer e Software Engineer
#Part-Time (verde):
#Em geral, representa os menores salários, como esperado.
#Um ponto curioso: Software Engineer part-time chega a ultrapassar $150k — isso pode ser por carga horária reduzida em empresas de alto valor agregado.
Gráfico de pizzas - Média salarial por modelo de trabalho (remoto=fully remote/híbrido=hybrid/presencial=on-site)¶
In [150]:
fig = px.pie(
df,
names='remote_ratio', # o que vai nas fatias
values='salary_in_usd', # peso de cada fatia (pode ser contagem também)
title='Distribuição de Salários por Modelo de Trabalho',
hole=0.3 # se quiser tipo "donut", senão tira isso
)
fig.show()
In [ ]:
#1. On-Site (Presencial) – 79,9%
#A maior parte dos salários está concentrada em empregos presenciais.
#Isso pode indicar:
#Maior número de posições presenciais no dataset.
#Ou que as empresas pagam mais no modelo presencial, talvez por funções mais tradicionais ou de liderança que exigem presença física.
#2. Fully Remote (100% Remoto) – 20%
#Apesar de todo o crescimento do trabalho remoto nos últimos anos, a fatia de distribuição de salários ainda é significativamente menor.
#Pode sugerir:
#Menor número de vagas 100% remotas bem remuneradas.
#Ou que empresas ainda oferecem salários menores nesse modelo (em alguns casos, compensado por benefícios como flexibilidade).
#3. Hybrid (50% Remoto) – 0,17%
#Praticamente inexistente no gráfico.
#Isso pode indicar duas coisas:
#O dataset tem pouquíssimos registros híbridos.
#Ou essas posições pagam valores muito baixos comparativamente.
Gráfico média de salários em relação ao tamanho da companhia¶
In [159]:
salario_por_tamanho_df = salario_por_tamanho.reset_index()
# Gráfico de barras
fig = px.bar(
salario_por_tamanho_df,
x='company_size',
y='salary_in_usd',
title='Média Salarial por Tamanho da Empresa',
labels={'company_size': 'Tamanho da Empresa', 'salary_in_usd': 'Salário Médio (USD)'},
color='company_size',
text_auto='.2s'
)
fig.update_layout(showlegend=False)
fig.show()
In [ ]:
#1. Mid-Sized Company (Empresa de Médio Porte) – 160k USD
#Maior média salarial entre os três portes.
#Pode indicar que empresas de médio porte:
#Estão em fase de crescimento acelerado e precisam atrair talentos com salários competitivos.
#São mais flexíveis em negociação de salário do que grandes corporações.
#2. Large Enterprise (Grande Empresa) – 150k USD
#Apesar de terem mais recursos, ficam atrás das médias empresas.
#Explicações possíveis:
#Mais estrutura e faixas salariais padronizadas.
#Benefícios indiretos compensam parte do salário direto.
#Grande número de cargos de entrada pode puxar a média para baixo.
#3. Small Business (Pequena Empresa) – 90k USD
#Menor média salarial.
#Natural, já que pequenas empresas:
#Têm menos capital disponível.
#Podem oferecer salários menores, mas compensar com flexibilidade, cultura ou participação societária (em alguns casos).
Média salarial por tipo de contrato e Nível de Experiência
In [162]:
# Cria DataFrame com médias por tipo de contrato + nível de experiência
media_contrato_experiencia = df.groupby(['employment_type', 'experience_level'])['salary_in_usd'].mean().reset_index()
# Gráfico de barras agrupadas
plt.figure(figsize=(12, 6))
sns.barplot(
data=media_contrato_experiencia,
x='employment_type',
y='salary_in_usd',
hue='experience_level',
palette='Set2'
)
plt.title('Média Salarial por Tipo de Contrato e Nível de Experiência', fontsize=14, fontweight='bold')
plt.xlabel('Tipo de Contrato')
plt.ylabel('Salário Médio (USD)')
plt.legend(title='Nível de Experiência')
plt.tight_layout()
plt.show()
In [ ]:
#Contract-Based
#Executive Director lidera, com média salarial acima de 190k USD.
#Senior Expert também se destaca, perto de 120k USD.
#Esse tipo de contrato pode envolver consultorias de alto nível ou projetos temporários bem remunerados.
#Freelance
#Média salarial mais baixa, especialmente para níveis mais altos.
#Pode indicar que:
#Muitos freelancers ainda estão em início de carreira ou atuam em projetos curtos.
#Ou que há grande variabilidade nos ganhos (nem todos ganham valores altos com consistência).
#Junior e Senior Expert ficam entre 55k–65k USD.
#Part-Time
#Faixas mais compactas e médias salariais mais baixas que as outras categorias.
#Mesmo um Senior Expert ganha menos de 130k USD.
#Pode indicar que cargos de meio período oferecem menos retorno financeiro direto, ainda que tenham mais flexibilidade.
#Full-Time
#Apresenta os valores mais altos em todas as categorias, especialmente:
#Executive Director: ultrapassa os 200k USD.
#Senior Expert: por volta de 175k USD.
#Evidencia que a carreira tradicional (full-time) continua sendo a que oferece maior retorno financeiro, principalmente com mais experiência.
Gráfico - Média salarial ao longo dos anos (cargo)¶
In [165]:
plt.figure(figsize=(14, 7))
sns.lineplot(
data=df_filtrado,
x='work_year',
y='salary_in_usd',
hue='job_title',
estimator='mean',
errorbar=None, # <- substitui ci=None
marker='o'
)
plt.title('Evolução da Média Salarial por Cargo ao Longo dos Anos', fontsize=14, fontweight='bold')
plt.xlabel('Ano')
plt.ylabel('Salário Médio (USD)')
plt.legend(title='Cargo')
plt.grid(True, linestyle='--', alpha=0.5)
plt.tight_layout()
plt.show()
In [ ]:
#Destaques e Tendências por Cargo
#Machine Learning Engineer
#Em 2020, tinha o maior salário (acima de 240k USD!), mas despencou em 2021.
#Depois disso, recuperou bem e se estabilizou entre 190k–200k USD até 2025.
#Indica uma possível bolha ou pico de valorização em 2020, seguida de ajuste.
#Data Scientist & Software Engineer
#Seguem trajetórias similares: queda leve em 2021, forte alta em 2022, e estabilidade nos últimos anos.
#Em 2025, ambos estão acima de 180k USD, o que mostra alta valorização do conhecimento técnico aplicado.
#Manager
#Crescimento bem marcado entre 2021 e 2023.
#Se mantém no topo dos salários em 2024 e 2025, chegando aos 200k USD.
#Confirma que cargos de liderança técnica continuam muito valorizados.
#Data Engineer
#Crescimento constante desde 2021.
#Em 2025, se aproxima de 150k USD, o que mostra que a área está em ascensão e valorizada.
#Research Scientist
#Cresce até 2023, mas começa a cair em 2024–2025, ficando abaixo de 150k USD.
#Pode indicar menor demanda em setores mais acadêmicos ou de pesquisa pura.
#Engineer (genérico) e Data Analyst
#Têm os salários mais baixos da lista.
#Data Analyst fica abaixo de 100k USD em todos os anos, com leve declínio em 2025.
#Isso reforça a ideia de que quanto mais especializada a função, maior a remuneração.